package com.mjk.manager.workflow.parser.sql.parse.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.mjk.common.base.error.BizException;
import com.mjk.common.base.work.annotation.BeeWork;
import com.mjk.common.tools.logger.BizLogger;
import com.mjk.common.util.AopTargetUtils;
import com.mjk.common.util.ObjectUtils;
import com.mjk.common.util.StrUtils;
import com.mjk.manager.workflow.parser.sql.parse.ILiteParse;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

import com.ql.util.express.ExpressRunner;
import com.ql.util.express.InstructionSet;
import com.yomahub.liteflow.flow.FlowBus;

import groovy.lang.GroovyClassLoader;

/**
 * 对于work#method 解析
 * @author Administrator
 *
 */
@Component
public class WorkFlowParse implements ApplicationContextAware, ILiteParse {
	public final static String WORK_FLOW_MARK = "#";
	/**	
	 * work 业务流 代码生成
	 */
	public final static String WORK_FLOW =
            """
                    package com.ld.manager.workflow.component;\r
                    import java.lang.reflect.Method;\r
                    import com.ld.common.util.BeanUtils;\r
                    import com.ld.common.util.LambdaReflectionUtil;\r
                    import com.ld.common.util.ReflectionUtils;\r
                    import com.yomahub.liteflow.annotation.LiteflowComponent;\r
                    import com.yomahub.liteflow.core.NodeComponent;\r
                    @LiteflowComponent(name = "%s")\r
                    public class %s extends NodeComponent implements BaseFlow{\r
                    	@Override\r
                    	public void process() throws Exception {\r
                    		Object target = this.flowMap.get("%s");\r
                    		Method m = ReflectionUtils.getAccessibleMethodByName(target, "%s");\r
                    		Class<?> clazz = BeanUtils.getClass(m.getParameters()[0].getParameterizedType().getTypeName());	\r
                    		LambdaReflectionUtil.invoke(target, "%s", conver2Paramters(this.getFirstContextBean(),clazz));\r
                    	}\r
                    }""";
	/**
	 * 保存的业务流类
	 */
    final Map<String,Object> FLOWMAP = new HashMap<>();
	/**
	 * 上下文
	 */
	private ConfigurableApplicationContext context;
	/**
	 * 解析脚本 生产node类 并返回正确的表达式
     */
	public void parse(Map<String, String> chainMap) {
		for(Entry<String,String> entry : chainMap.entrySet()) {
			 String express = entry.getValue();
			 ExpressRunner runner = new ExpressRunner();
			 try {
				 InstructionSet set = runner.getInstructionSetFromLocalCache(express);
				 //获取节点信息
				 if(null!=set && !ObjectUtils.isEmpty(set.getOutAttrNames())) {
					 for(String str : set.getOutAttrNames()) {
						  buildFlowByAttrName(str); 
			         }
				 }
			 }catch(Exception e) {
				 throw new BizException("node parse error" + ExceptionUtil.getMessage(e));
			 }
		}
	}
	
	/**
	 * 构建业务流类
     */
	public void  buildFlowByAttrName(String attrName) {
		if(attrName.contains(WORK_FLOW_MARK)) { //如果包含. 则需要分割. 左边为work 右边为method
			String[] work = attrName.split(WORK_FLOW_MARK);
			if(work.length==2) {//如果包含了多个# 不处理
				//判断 work中是否存在 并且在 业务流中不存在
				if(FLOWMAP.containsKey(work[0]) && !FlowBus.containChain(attrName)) {
					String name = attrName.replace(WORK_FLOW_MARK, "");
					String clazzStr = String.format(WorkFlowParse.WORK_FLOW, attrName, StrUtils.toUpperCaseFirstOne(name),work[0],work[1],work[1]);
					try(GroovyClassLoader groovyClassLoader = new GroovyClassLoader();) {
						Class clazz = groovyClassLoader.parseClass(clazzStr);
						BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
						BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
						BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) context.getBeanFactory();
						beanFactory.registerBeanDefinition(attrName, beanDefinition);
						FlowBus.addManagedNode(attrName);
					}catch (Exception e){
						BizLogger.error(e);
					}
				}
			}
		}
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.context = (ConfigurableApplicationContext) applicationContext;
		Map<String,Object> works = applicationContext.getBeansWithAnnotation(BeeWork.class);
		for(Entry<String,Object> entry : works.entrySet()){
			Object target = AopTargetUtils.getTarget(entry.getValue());
			BeeWork work = Objects.requireNonNull(target).getClass().getAnnotation(BeeWork.class);
			FLOWMAP.put(work.work(),target);
		}
	}
}
